package com.gss.armory.persistence;


import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;
import com.gss.armory.domain.DocAttDTO;
import com.gss.armory.domain.DocGeneralDetailsDTO;
import com.gss.armory.domain.DocGeneralDetailsDTO.DocumentFlowStatus;
import com.gss.armory.domain.DocReviewerApproverForWFDTO;
import com.gss.armory.domain.DocumentAuthSignatoryDTO;
import com.gss.armory.domain.DocumentCustodianDetailsDTO;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO.WorkflowEventStatus;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO.WorkflowStatus;
import com.gss.armory.domain.MasterDetailsForDMSWFDTO.attributes;
import com.gss.armory.domain.UserActivityGroup;
import com.gss.armory.domain.UserActivityGroup.DocActivityType;
import com.gss.common.util.ApplicationMaps;
import com.gss.common.util.ApplicationUtilities;


	@Repository
	public class WorkFlowDAO  extends HibernateDaoSupport{
		
		private Logger logger = Logger.getLogger(CommonDAO.class);
		
		@Autowired
		public WorkFlowDAO(SessionFactory sessionFactory){
			super.setSessionFactory(sessionFactory);
			logger.debug("inside workflow dao");
		}

		
		public List loadAll(Class entityClass) throws Exception{
			List results;
			logger.debug("inside method loadAll for: " + entityClass.getCanonicalName());
				try {
					//DetachedCriteria criteria = DetachedCriteria.forClass(entityClass);
					results = getHibernateTemplate().loadAll(entityClass);
					logger.debug("number of records:" + results.size());
					return results;
				} catch (Throwable e) {
					//e.printStackTrace();
					logger.error(e.getMessage());
				}
			return null;
		}


		public  List<DocAttDTO> getDocDetail(long docId) throws Exception
		{
			logger.debug("inside method of getWorkFlowDetails for: ");
			DetachedCriteria criteria = DetachedCriteria.forClass(DocAttDTO.class);
			criteria.add(Restrictions.eq("doc_id",docId));
			return getHibernateTemplate().findByCriteria(criteria);
		}

		public  List<DocumentWorkflowDetailsDTO> getWorkFlowDetails() throws Exception
		{
			logger.debug("inside method of getWorkFlowDetails for: ");
			DetachedCriteria criteria = DetachedCriteria.forClass(DocumentWorkflowDetailsDTO.class);
			criteria.add(Restrictions.eq("wfAssignedUser", ApplicationUtilities.getCurrentUser()));
			
			criteria.add(Restrictions.eq("wfEventStatus", WorkflowEventStatus.OPEN));
			return getHibernateTemplate().findByCriteria(criteria);
		}
		
		public  List<DocumentWorkflowDetailsDTO> copyGetWorkFlowDetails(DetachedCriteria criteria) throws Exception
		{
			try{
				return getHibernateTemplate().findByCriteria(criteria);
			}
			catch(Exception e){
				logger.error(e.getMessage(),e);
			}
			return null;
		}
		
		

		public Boolean updateWfEventStatus(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
			detailsDTO.setWfEventStatus(WorkflowEventStatus.CLOSED);
			updateDocumentWFDetails(detailsDTO);
			return true;
		}

		public Boolean updateDocStatus(DocumentWorkflowDetailsDTO detailsDTO,DocGeneralDetailsDTO generalDetailsDTO) throws Exception {
			detailsDTO.setWfEventStatus(WorkflowEventStatus.CLOSED);
			detailsDTO.setUpdatedDate(new Date());
			detailsDTO.setStrUpdatedAuthor(ApplicationUtilities.getCurrentUser());
			detailsDTO.setVersion(detailsDTO.getVersion() + 1);
			if(detailsDTO.getWfStatus().equals(WorkflowStatus.PFA))
			{			
				generalDetailsDTO.setDocumentStatus(DocumentFlowStatus.Active);
				generalDetailsDTO.setDocCode(ApplicationUtilities.generateDocumentCode(generalDetailsDTO));
				updateDocgeneralDetails(generalDetailsDTO);
				logger.debug(generalDetailsDTO.getDocCode());
			}
			updateDocumentWFDetails(detailsDTO);
			return true;
		}
		
		public void updateDocgeneralDetails(
				DocGeneralDetailsDTO generalDetailsDTO) throws Exception{
			getHibernateTemplate().update(generalDetailsDTO);
			
		}


		public void loadDocGeneralDetals(DocGeneralDetailsDTO generalDetailsDTO) throws Exception {
			getHibernateTemplate().load(generalDetailsDTO, generalDetailsDTO.getDocId());
			
		}


		public void saveVaultDetails(
				DocumentCustodianDetailsDTO custodianDetailsDTO) throws Exception {
			if(custodianDetailsDTO.getVaultId() != 0)
					getHibernateTemplate().update(custodianDetailsDTO);
			else
				getHibernateTemplate().save(custodianDetailsDTO);
		}


		private void updateDocumentWFDetails(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
			getHibernateTemplate().update(detailsDTO);
			
		}


		public void loadWorkflowDetails(DocumentWorkflowDetailsDTO detailsDTO) throws Exception{
			getHibernateTemplate().load(detailsDTO, detailsDTO.getWfId());
		}


		public DocAttDTO loadDocAtrrdetail(long docId) throws Exception{
			DetachedCriteria criteria = DetachedCriteria.forClass(DocAttDTO.class);
			
			logger.debug("Doc Att Dto "+docId);
			criteria.add(Restrictions.eq("doc_id", docId));
			return (DocAttDTO) getHibernateTemplate().findByCriteria(criteria).get(0);
		}

		public void loadDocumentDetails(DocGeneralDetailsDTO docGeneralDetailsDTO) throws Exception{
			logger.debug("inside the loadDocumentDetails");
			getHibernateTemplate().load(docGeneralDetailsDTO, docGeneralDetailsDTO.getDocId());
		}
		

		public DocumentWorkflowDetailsDTO createWfRowForSubmit(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
			DocumentWorkflowDetailsDTO newWfDTO= new DocumentWorkflowDetailsDTO();
			newWfDTO.setDocId(detailsDTO.getDocId());
			newWfDTO.setDocName(detailsDTO.getDocName());
			newWfDTO.setVersion(1);
			newWfDTO.setCreatedDate(new Date(System.currentTimeMillis()));
			newWfDTO.setStrCreatedAuthor(ApplicationUtilities.getCurrentUser());
//			newWfDTO.setStrUpdatedAuthor(ApplicationUtilities.getCurrentUser());
			newWfDTO.setRemarks("new entry");
			newWfDTO.setCreatorRemarks(detailsDTO.getRemarks());

			if(detailsDTO.getWfStatus().equals(WorkflowStatus.PFS)||detailsDTO.getWfStatus().equals(WorkflowStatus.PFRS))
			{
				logger.debug("submitting for reviewing");
				newWfDTO.setWfStatus(WorkflowStatus.PFR);
				newWfDTO.setWfEventStatus(WorkflowEventStatus.OPEN);
				newWfDTO.setWfAssignedUser(getReviewer(detailsDTO)); // "2" later will use function to get reviewer
			}
			else if(detailsDTO.getWfStatus().equals(WorkflowStatus.PFR )||detailsDTO.getWfStatus().equals(WorkflowStatus.PFRR))
			{
				logger.debug("reviewing for approve");
				newWfDTO.setWfStatus(WorkflowStatus.PFA);
				newWfDTO.setWfEventStatus(WorkflowEventStatus.OPEN);
				newWfDTO.setWfAssignedUser(getApprover(detailsDTO)); // "3" later will use function to get approval
			}
			saveWfRow(newWfDTO);
			return newWfDTO;
		}
		
		public void createWFRowForRenewableDocument(DocumentWorkflowDetailsDTO detailsDTO,DocGeneralDetailsDTO docGeneralDetailsDTO) throws Exception {
			DocumentWorkflowDetailsDTO newWfDTO= new DocumentWorkflowDetailsDTO();
			newWfDTO.setDocId(detailsDTO.getDocId());
			newWfDTO.setDocName(detailsDTO.getDocName());
			newWfDTO.setVersion(1);
			newWfDTO.setCreatedDate(docGeneralDetailsDTO.getDocValidityEndDate());
			newWfDTO.setStrCreatedAuthor("system generated");
			newWfDTO.setUpdatedDate(new Date(docGeneralDetailsDTO.getDocValidityEndDate().getTime() - 
					(docGeneralDetailsDTO.getFirstEscalationPeriod() * 24 * 60 * 60 * 1000)));
			newWfDTO.setRemarks("entry for renewable docs");
			newWfDTO.setCreatorRemarks(detailsDTO.getRemarks());
			newWfDTO.setWfEventStatus(WorkflowEventStatus.OPEN);
			newWfDTO.setWfStatus(WorkflowStatus.TBR); // to be renewed
			//newWfDTO.setWfAssignedUser(wfAssignedUser);
			saveWfRow(newWfDTO);
		}

		public DocumentWorkflowDetailsDTO createWfRowForReject(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
			DocumentWorkflowDetailsDTO newWfDTO= new DocumentWorkflowDetailsDTO();
			newWfDTO.setDocId(detailsDTO.getDocId());
			newWfDTO.setDocName(detailsDTO.getDocName());
			newWfDTO.setVersion(1);
			newWfDTO.setCreatedDate(new Date());
			newWfDTO.setStrCreatedAuthor(ApplicationUtilities.getCurrentUser());
//			newWfDTO.setStrUpdatedAuthor(ApplicationUtilities.getCurrentUser());
			newWfDTO.setCreatorRemarks(detailsDTO.getRemarks());
			newWfDTO.setRemarks("new entry");
//			newWfDTO.setUpdatedDate(new Date());
			
			if(detailsDTO.getWfStatus().equals(WorkflowStatus.PFR)||detailsDTO.getWfStatus().equals(WorkflowStatus.PFRR))
			{
				newWfDTO.setWfStatus(WorkflowStatus.PFRS);
				newWfDTO.setWfEventStatus(WorkflowEventStatus.OPEN);
				newWfDTO.setWfAssignedUser(getUploader(detailsDTO)); // "2" later will use function to get uploader
			}
			else if(detailsDTO.getWfStatus().equals(WorkflowStatus.PFA ))
			{
				newWfDTO.setWfStatus(WorkflowStatus.PFRR);
				newWfDTO.setWfEventStatus(WorkflowEventStatus.OPEN);
				newWfDTO.setWfAssignedUser(getReviewer(detailsDTO)); // "2" later will use function to get reviewer
			}
	
			saveWfRow(newWfDTO);
			return newWfDTO;
		}

		public boolean updateDocRow(DocAttDTO docAtt) {
			try
			{
				getHibernateTemplate().update(docAtt);
				return true;
			}
			catch(DataAccessException e)
			{
				//e.printStackTrace();
				logger.error(e.getMessage());
				return false;
			}
			
		}
		private void saveWfRow(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
			getHibernateTemplate().save(detailsDTO);
			
		}
		
		private void saveDocRow(DocAttDTO docAtt) throws Exception {
			getHibernateTemplate().update(docAtt);
			
		}
		
		public String getReviewer(DocumentWorkflowDetailsDTO detailsDTO) throws Exception
		{
			String masterCode = getMasterCodeForDocument(detailsDTO);
			DocReviewerApproverForWFDTO approverForWFDTO = new DocReviewerApproverForWFDTO();
			approverForWFDTO.setMasterCode(masterCode);
			getReviewerAndApproverDto(approverForWFDTO);
			logger.debug("Reviever  "+approverForWFDTO.getReviewer());
			return approverForWFDTO.getReviewer(); 
		}
		public String getApprover(DocumentWorkflowDetailsDTO detailsDTO) throws Exception
		{
			String masterCode = getMasterCodeForDocument(detailsDTO);
			DocReviewerApproverForWFDTO approverForWFDTO = new DocReviewerApproverForWFDTO();
			approverForWFDTO.setMasterCode(masterCode);
			getReviewerAndApproverDto(approverForWFDTO);
			logger.debug("Approver  "+approverForWFDTO.getApprover());
			return approverForWFDTO.getApprover();
		}

		public String getController() throws Exception
		{
			return "333";
		}
		public String getUploader(DocumentWorkflowDetailsDTO detailsDTO) throws Exception
		{
			DocGeneralDetailsDTO detailsDTO2 = new DocGeneralDetailsDTO();
			detailsDTO2.setDocId(detailsDTO.getDocId());
			loadDocGeneralDetals(detailsDTO2);
			logger.debug(detailsDTO2.getStrCreatedAuthor());
			return detailsDTO2.getStrCreatedAuthor(); 
		}
		public void getReviewerAndApproverDto(DocReviewerApproverForWFDTO approverForWFDTO) throws Exception{
			getHibernateTemplate().load(approverForWFDTO, approverForWFDTO.getMasterCode());
		}



		public void saveWFRoleDetails(DocReviewerApproverForWFDTO docReviewerApproverForWFDTO) throws Exception {
			
			getHibernateTemplate().saveOrUpdate(docReviewerApproverForWFDTO);
		}

		

		public String getMasterCodeForDocument(DocumentWorkflowDetailsDTO detailsDTO) throws Exception{
			DocGeneralDetailsDTO detailsDTO2 = new DocGeneralDetailsDTO();
			detailsDTO2.setDocId(detailsDTO.getDocId());
			loadDocGeneralDetals(detailsDTO2);
			StringBuffer buffer = new StringBuffer();
			if(ApplicationMaps.ARMORY_MASTER_DATA.get(attributes.Type)){
				buffer.append(detailsDTO2.getDocTypeId());
			}
			if(ApplicationMaps.ARMORY_MASTER_DATA.get(attributes.Location)){
				if(null!=buffer && buffer.length()>0)
					buffer.append("#"+detailsDTO2.getDocLocId());
				else
					buffer.append(detailsDTO2.getDocLocId());
			}
			if(ApplicationMaps.ARMORY_MASTER_DATA.get(attributes.Department)){
				if(null!=buffer && buffer.length()>0)
					buffer.append("#"+detailsDTO2.getDocDepttId());
				else
					buffer.append(detailsDTO2.getDocDepttId());
			}
			return buffer.toString();
		}


		public List<DocActivityType> userActivityForDocument(long docId, String userName) throws Exception {
			DetachedCriteria criteria = DetachedCriteria.forClass(UserActivityGroup.class);
			criteria.add(Restrictions.eq("username", userName));
			criteria.add(Restrictions.eq("docId", docId));
			criteria.setProjection(Projections.property("activityType"));
			List<DocActivityType> list =  getHibernateTemplate().findByCriteria(criteria);
			
			return list;
		}


		public void saveAuthSignatory(
				List<DocumentAuthSignatoryDTO> authSignatoryList) throws Exception {
			getHibernateTemplate().saveOrUpdateAll(authSignatoryList);
		}


		public List<DocumentAuthSignatoryDTO> getDocumentAuthSignatory(
				long docId) throws Exception {
			DetachedCriteria criteria = DetachedCriteria.forClass(DocumentAuthSignatoryDTO.class);
			criteria.add(Restrictions.eq("docId", docId));
			return getHibernateTemplate().findByCriteria(criteria);
		}

	}



